﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using grounding.nao;
using grounding.nao.sensors;
using grounding.grounder;
using grounding.parser.Parsers;
using System.Threading;
using grounding.nao.enums;
using grounding.parser;
using Accord.Statistics.Kernels;

namespace grounding.tests.DataGatherer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Nao nao;
        private Category category;
        private Dictionary<Category, TrainingData> data = new Dictionary<Category,TrainingData>();
        private SVMGrounder grounder = null;
        private Dictionary<Category, ListBoxItem> classificationItems = new Dictionary<Category, ListBoxItem>();
        private Mutex panicMutex = new Mutex();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Setup comboboxes & listbox
            foreach (Category cat in Category.Categories)
            {
                category_box.Items.Add(cat.Element);

                classificationItems.Add(cat, new ListBoxItem() { Content = string.Format("{0,10} : Not Learned", cat) });
                classifications.Items.Add(classificationItems[cat]);
            }

            Dictionary<Sensor, Func<IEnumerable<double>, IEnumerable<double>>> transformers = new Dictionary<Sensor, Func<IEnumerable<double>, IEnumerable<double>>>()
            {
                {Sensor.JointCurrentSensor, x => new double[] { x.Average() } },
                {Sensor.FootSensor, x => new double[] { x.Average() } },
                {Sensor.TemperatureSensor, x => new double[] { x.Average() } }
            };

            nao = new Nao("128.208.6.22", 9559, transformers: transformers, 
                active: new Sensor[] {
                    Sensor.FootSensor,
                    Sensor.Sonar});
            if (nao.IsConnected)
            {
                status.Content = "Status: Connected";
                //nao.SensorFrameReceived += new EventHandler<NaoSensorFrame>(nao_SensorFrameReceived);
            }
        }

        void nao_SensorFrameReceived(object sender, NaoSensorFrame e)
        {
            panicMutex.WaitOne();

            if (grounder != null)
            {
                var result = grounder.Test(nao.GetSensorFrame().ToArray());

                foreach (grounding.parser.Parsers.Label label in result.Keys)
                {
                    classificationItems[label.Parent].Content = string.Format("{0,15} : {1,-15}", label.Parent.Element, label.Element);
                }
            }

            panicMutex.ReleaseMutex();
        }

        private void begin_training_Click(object sender, RoutedEventArgs e)
        {
            if (category_box.SelectedIndex != -1 && training_name.Text.Length != 0)
            {
                // Begin training.
                category_box.IsEnabled = false;
                training_name.IsEnabled = false;
                begin_training.IsEnabled = false;
                category = Category.GetCategory((string)category_box.SelectedItem);
                data.Add(category, new TrainingData(training_name.Text, category.Identifier));

                train_positive.Content = category.Positive.Element;
                train_negative.Content = category.Negative.Element;
                train_positive.IsEnabled = true;
                train_negative.IsEnabled = true;
                complete.IsEnabled = true;
            }
        }

        private void save_Click(object sender, RoutedEventArgs e)
        {
            parser.Parsers.Label label;
            if(sender == train_positive)
                label = category.Positive;
            else
                label = category.Negative;

            int repetitions = int.Parse(frameCount.Text);

            var frames = nao.GetSensorFrames(repetitions, 200);

            foreach(ISensorFrame frame in frames)
            {
                data[category].AddExample(frame, label);

                string dataEntry = "";
                dataEntry += string.Format("{0, 10} : ", label.Element);
                foreach (double x in frame.ToArray())
                    dataEntry += string.Format("{0,4:0.00}, ", x);

                data_field.Items.Add(new ListViewItem() { Content = dataEntry });
            }
        }

        private void complete_Click(object sender, RoutedEventArgs e)
        {
            data[category].SaveToDisk();

            category_box.SelectedIndex = -1;
            category_box.IsEnabled = true;
            training_name.Text = "";
            training_name.IsEnabled = true;
            train_positive.Content = "";
            train_positive.IsEnabled = false;
            train_negative.Content = "";
            train_negative.IsEnabled = false;
            data_field.Items.Clear();
            begin_training.IsEnabled = true;
        }

        private void Train_Click(object sender, RoutedEventArgs e)
        {
            IKernel svmKernel = null;
            if (svmGaussianKernel.IsChecked.Value)
                svmKernel = new Gaussian(double.Parse(svmSigma.Text));
            if (svmPolynomialKernel.IsChecked.Value)
                svmKernel = new Polynomial(int.Parse(svmDegree.Text));
            if (svmLinearKernel.IsChecked.Value)
                svmKernel = new Linear();

            IKernel pcaKernel = null;
            if (pcaGaussianKernel.IsChecked.Value)
                pcaKernel = new Gaussian(double.Parse(pcaSigma.Text));
            if (pcaPolynomialKernel.IsChecked.Value)
                pcaKernel = new Polynomial(int.Parse(pcaDegree.Text));
            if (pcaLinearKernel.IsChecked.Value)
                pcaKernel = new Linear();

            if (svmKernel != null && pcaKernel != null)
            {
                grounder = new SVMGrounder(svmKernel, pcaKernel, int.Parse(featureCount.Text));

                grounder.Train(data.Values.ToList());


            }
        }

        private void loadFile_Click(object sender, RoutedEventArgs e)
        {
            panicMutex.WaitOne();

            TrainingData newData = TrainingData.LoadFromDisk(trainingName.Text);
            Category cat = Category.GetCategory(newData.Category);

            if (data.ContainsKey(cat))
                data[cat].Add(newData);
            else
                data.Add(cat, newData);

            for (int i = 0; i < newData.Classes.Length; i++)
            {
                string dataEntry = "";
                dataEntry += string.Format("{0, 10} : ", grounding.parser.Parsers.Label.GetLabel(Category.GetCategory(newData.Category), newData.Classes[i]).Element);
                foreach (double x in newData.DataVector[i])
                    dataEntry += string.Format("{0,4:0.00}, ", x);

                data_field.Items.Add(new ListViewItem() { Content = dataEntry });
            }

            testBtn.IsEnabled = true;

            panicMutex.ReleaseMutex();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            nao_SensorFrameReceived(this, (NaoSensorFrame)nao.GetSensorFrame());
        }
    }
}
